package com.example.clock_demo.listener;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.clock_demo.entitys.Scheduling;
import com.example.clock_demo.entitys.Shift;
import com.example.clock_demo.service.SchedulingService;
import com.example.clock_demo.service.ShiftService;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.util.Objects;



@Slf4j
public class SchedulingImportListener extends AnalysisEventListener<Map<Integer, String>> {

    private final SchedulingService schedulingService;
    private final ShiftService shiftService;
    private final YearMonth importMonth;
    private final List<Scheduling> schedulingList = new ArrayList<>();
    private final Map<String, Shift> shiftCodeCache = new HashMap<>();


    private static final int START_DAY_COLUMN_INDEX_0BASED = 5; // Excel中第6列

    private boolean headerValidatedSuccessfully = false;

    public SchedulingImportListener(SchedulingService schedulingService, ShiftService shiftService, YearMonth importMonth) {
        this.schedulingService = schedulingService;
        this.shiftService = shiftService;
        this.importMonth = importMonth;
        initShiftCache();
    }

    private void initShiftCache() {
        try {
            List<Shift> allShifts = shiftService.list();
            for (Shift shift : allShifts) {
                if (StrUtil.isNotBlank(shift.getShiftCode())) {
                    shiftCodeCache.put(shift.getShiftCode(), shift);
                }
            }
            log.info("班次缓存初始化完成，共缓存{}个班次", shiftCodeCache.size());
        } catch (Exception e) {
            log.error("初始化班次缓存失败", e);
            throw new RuntimeException("初始化班次信息失败，无法进行排班导入。", e);
        }
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        int currentRowIndex = context.readRowHolder().getRowIndex();
        log.info("### invokeHeadMap 被调用，当前行索引：{}", currentRowIndex);
        log.info("### 当前行完整表头内容 headMap: {}", headMap);


        if (currentRowIndex == 2) { // 检查是否是包含日期表头的那一行
            log.info("正在校验Excel表头，当前处理的行索引：{}", currentRowIndex);
            boolean isTemplateValid = true;
            StringBuilder errorDetails = new StringBuilder("表头缺少或不正确的日期列: ");

            // 校验从第6列（索引5）到第36列（索引35）的表头
            for (int day = 1; day <= 31; day++) {
                int colIndex = START_DAY_COLUMN_INDEX_0BASED + day - 1; // 计算当前日期对应的列索引
                String expectedHeader = String.valueOf(day);

                String actualHeader = headMap.get(colIndex);

                if (actualHeader == null || !Objects.equals(expectedHeader, actualHeader.trim())) {
                    isTemplateValid = false;
                    errorDetails.append("[日期 ").append(day).append(" (列 ").append(colIndex + 1).append(")");
                    if (actualHeader == null) {
                        errorDetails.append(" 缺失]");
                    } else {
                        errorDetails.append(" 实际值:'").append(actualHeader).append("'");
                    }
                    errorDetails.append("; ");
                    log.warn("表头校验失败：期望 '{}' 但实际为 '{}' (列索引 {})", expectedHeader, actualHeader, colIndex);
                }
            }

            if (!isTemplateValid) {
                throw new RuntimeException("Excel 模板格式不正确：" + errorDetails.toString());
            }
            log.info("Excel表头校验通过。");
            headerValidatedSuccessfully = true; // 标记表头校验成功
        } else {
            log.info("非日期表头行，跳过校验。当前行索引：{}", currentRowIndex);
        }
    }
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        if (!headerValidatedSuccessfully) {
            log.error("表头校验未通过或文件无表头，跳过数据行处理。");
            return;
        }

        if (data == null || data.isEmpty()) {
            return;
        }


        int rowIndex = context.readRowHolder().getRowIndex();
        if (rowIndex < 3) {
            return;
        }

        try {
            // 班组名称 (B列，索引1)
            String teamName = data.get(1);
            // 班组编号 (C列，索引2)
            String teamCode = data.get(2);
            // 员工姓名 (D列，索引3)
            String employeeName = data.get(3);
            // 员工工号 (E列，索引4)
            String employeeNumber = data.get(4);

            if (StrUtil.isBlank(employeeName) || StrUtil.isBlank(employeeNumber)) {
                log.warn("第 {} 行数据员工姓名或工号为空，跳过此行。", rowIndex + 1);
                return;
            }

            // 解析班次代码（从第6列（索引5）开始对应1-31日）
            int daysInMonth = importMonth.lengthOfMonth();
            for (int day = 1; day <= daysInMonth; day++) {

                String shiftCode = data.get(START_DAY_COLUMN_INDEX_0BASED + day - 1);
                if (StrUtil.isNotBlank(shiftCode)) {
                    Scheduling scheduling = new Scheduling();
                    scheduling.setTeamName(teamName);
                    scheduling.setTeamCode(teamCode);
                    scheduling.setEmployeeName(employeeName);
                    scheduling.setEmployeeNumber(employeeNumber);
                    scheduling.setScheduleDate(importMonth.atDay(day));
                    scheduling.setShiftCode(shiftCode);
                    String workLocation = data.get(36);
                    String offWorkLocation = data.get(37);
                    scheduling.setWorkLocation(workLocation);
                    scheduling.setOffWorkLocation(offWorkLocation);

                    BigDecimal workHours = getWorkHoursFromCache(shiftCode);
                    scheduling.setScheduledDurationHours(workHours);

                    schedulingList.add(scheduling);
                }
            }
        } catch (Exception e) {
            log.error("解析排班数据失败，行号：{}，原始数据：{}，错误：{}", rowIndex + 1, data, e.getMessage(), e);
            throw new RuntimeException("解析Excel数据失败，第 " + (rowIndex + 1) + " 行，原因：" + e.getMessage(), e);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (!headerValidatedSuccessfully) {
            throw new RuntimeException("Excel 模板校验未通过或文件为空，无法完成导入。");
        }

        if (!schedulingList.isEmpty()) {
            try {
                schedulingService.deleteByMonth(importMonth);
                schedulingService.saveBatch(schedulingList);
                log.info("排班数据导入完成，共导入{}条记录", schedulingList.size());
            } catch (Exception e) {
                log.error("保存排班数据失败", e);
                throw new RuntimeException("保存排班数据失败：" + e.getMessage(), e);
            }
        } else {
            log.warn("未解析到任何有效的排班数据。");
        }
    }

    private BigDecimal getWorkHoursFromCache(String shiftCode) {
        if (StrUtil.isBlank(shiftCode)) {
            return BigDecimal.ZERO;
        }

        Shift cachedShift = shiftCodeCache.get(shiftCode);
        if (cachedShift != null && cachedShift.getShiftDurationHours() != null) {
            return cachedShift.getShiftDurationHours();
        }

        try {
            Shift shift = shiftService.getShiftByCode(shiftCode);
            if (shift != null) {
                shiftCodeCache.put(shiftCode, shift);
                return shift.getShiftDurationHours() != null ? shift.getShiftDurationHours() : BigDecimal.ZERO;
            }
        } catch (Exception e) {
            log.error("获取班次信息失败，班次代码：{}，错误：{}", shiftCode, e.getMessage(), e);
        }

        log.warn("未找到班次代码为 {} 的班次信息，使用默认工时0.0。请检查班次配置。", shiftCode);
        return BigDecimal.ZERO;
    }
}